package com.dzirtbry.ticatac.ai;

import java.awt.Point;
import java.util.ArrayList;

import com.dzirtbry.ticatac.pane.TicTacMarker;
import com.dzirtbry.ticatac.pane.TicTacPane;

public final class AI {
	
	/**
	 *	No instance! 
	 */
	private AI() {}
	
	private static int[][] lines = {{3,2,3}, {2,4,2}, {3,2,3}};
	
	public static int getAllAvaliableLinesNumber(Point p) {
		return lines[p.x][p.y];
	}
	
	public static Point makeMove (TicTacPane pane, int turn) {
		// Opponents mark
		int opponent = turn == TicTacMarker.TIC ? TicTacMarker.TAC : TicTacMarker.TIC;
		
		// Check if there is a line without 1 point
		for (int i=0; i<3; i++) {
			for (int j=0; j<3; j++) {
				if (getNeedToComplete(pane, new Point(i, j), turn) == 1) 
					return new Point(i, j);
			}
		}
		
		// Check if opponent need last mark to victory
		for (int i=0; i<3; i++) {
			for (int j=0; j<3; j++) {
				if (getNeedToComplete(pane, new Point(i, j), opponent) == 1) 
					return new Point(i, j);
			}
		}
		
		// Get list of the best suggestions
		ArrayList<Point> bestPoints = getBestPoints(pane, turn);
		
		// Return suggested point
		return bestPoints.get((int) (Math.random()*bestPoints.size()));
	}
	
	private static ArrayList<Point> getBestPoints(TicTacPane pane, int turn) {
		ArrayList<Point> res = new ArrayList<Point>();
		ArrayList<Point> freePoints = pane.getFreePoints();
		
		if (freePoints.size() == 1) {
			return freePoints;
		}
		
		int bestNeeds = 4;
		for (Point p: freePoints) {
			int need = getNeedToComplete(pane, p, turn);
			if (need < bestNeeds) {
				bestNeeds = need;
				res.clear();
			}
			if (bestNeeds == need) {
				res.add(p);
			}
		}
		
		int bestAvaliables = 0;
		ArrayList<Point> res2 = new ArrayList<Point>();
		for (Point point: res) {
//			int t = getAvaliableLinesNumber(pane, point, turn);
			int t = getAllAvaliableLinesNumber(point);
			if (t > bestAvaliables) {
				bestAvaliables = t;
				res2.clear();
			}
			if (bestAvaliables == t) {
				res2.add (point);
			}
		}
		res.clear();
		
		bestAvaliables = 0;
		for (Point point: res2) {
			int t = getAvaliableLinesNumber(pane, point, turn);
//			int t = getAllAvaliableLinesNumber(point);
			if (t > bestAvaliables) {
				bestAvaliables = t;
				res.clear();
			}
			if (bestAvaliables == t) {
				res.add (point);
			}
		}

		return res;
	}
	
	private static int getAvaliableLinesNumber (TicTacPane pane, Point point, int marker) {
		int res = 0;
		res += pane.isColAvaliable(point.y, marker) ? 1:0;
		res += pane.isRowAvaliable(point.x, marker) ? 1:0;
		res += pane.isPointOnMainDiagonal(point) && pane.isMainDiagonalAvaliable(marker) ? 1:0;
		res += pane.isPointOnCounterDiagonal(point) && pane.isCounterDiagonalAvaliable(marker) ? 1:0;
		return res;
	}
	
	private static int getNeedToComplete(TicTacPane pane, Point point, int marker) {
		int res = 4;
		if (pane.getMarker(point) != TicTacMarker.NO) 
			return 4;
		res = Math.min(pane.isColAvaliable(point.y, marker) ? getNeedToColmpleteCol(pane, point.y):4, res);
		res = Math.min(pane.isRowAvaliable(point.x, marker) ? getNeedToColmpleteRow(pane, point.x):4, res);
		res = Math.min(pane.isMainDiagonalAvaliable(marker) && pane.isPointOnMainDiagonal(point) ? getNeedToColmpleteMainDiagonal(pane):4, res);
		res = Math.min(pane.isCounterDiagonalAvaliable(marker) && pane.isPointOnCounterDiagonal(point) ? getNeedToCompleteCounterDiagonal(pane):4, res);
		return res;
	}

	private static int getNeedToColmpleteCol (TicTacPane pane, int col) {
		int res = 3;
		for (int i=0; i<3; i++){
			if (pane.getMarker(new Point(i, col)) != TicTacMarker.NO) {
				res--;
			}
		}
		return res;
	}
	
	private static int getNeedToColmpleteRow (TicTacPane pane, int row) {
		int res = 3;
		for (int i=0; i<3; i++){
			if (pane.getMarker(new Point(row, i)) != TicTacMarker.NO) {
				res--;
			}
		}
		return res;
	}

	private static int getNeedToColmpleteMainDiagonal(TicTacPane pane) {
		int res = 3;
		for (int i=0; i<3; i++){
			if (pane.getMarker(new Point(i, i)) != TicTacMarker.NO) {
				res--;
			}
		}
		return res;
	}
	
	private static int getNeedToCompleteCounterDiagonal(TicTacPane pane) {
		int res = 3;
		for (int i=0; i<3; i++){
			if (pane.getMarker(new Point(i, 2-i)) != TicTacMarker.NO) {
				res--;
			}
		}
		return res;
	}

}
